package com.zb.nio.c4;

import static com.zb.nio.ByteBufferUtil.debugRead;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SelectServerV2 {
        public static void main(String[] args) {
            try (ServerSocketChannel channel = ServerSocketChannel.open()) {
                channel.bind(new InetSocketAddress(8080));
                System.out.println(channel);
                Selector selector = Selector.open();
                channel.configureBlocking(false);
                channel.register(selector, SelectionKey.OP_ACCEPT);

                while (true) {
                    int count = selector.select();
                    log.debug("select count: {}", count);

                    // 获取所有事件
                    Set<SelectionKey> keys = selector.selectedKeys();

                    // 遍历所有事件，逐一处理
                    Iterator<SelectionKey> iter = keys.iterator();
                    while (iter.hasNext()) {
                        SelectionKey key = iter.next();
                        // 判断事件类型
                        if (key.isAcceptable()) {
                            ServerSocketChannel c = (ServerSocketChannel) key.channel();
                            // 必须处理
                            SocketChannel sc = c.accept();
                            sc.configureBlocking(false);
                            sc.register(selector, SelectionKey.OP_READ);
                            log.debug("连接已建立: {}", sc);
                        } else if (key.isReadable()) {
                            SocketChannel sc = (SocketChannel) key.channel();
                            ByteBuffer buffer = ByteBuffer.allocate(128);
                            int read = sc.read(buffer);
                            // 客户端断开，read的方法的返回值是-1。异常断开的化会抛出IO异常
                            if(read == -1) {
                                // 客户端断开会一直触发read，所以需要手动取消
                                key.cancel();
                                sc.close();
                            } else {
                                buffer.flip();
                                debugRead(buffer);
                            }
                        }
                        // 处理完毕，必须将事件移除
                        iter.remove();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
